package com.pomelo.base.core.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.*;
import java.util.Map.Entry;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

/**
 * 工具类
 *
 * @author biankudingcha
 * @date: 2021-07-26
 * @since 0.5.0
 */
public final class CommonUtil {

    /**
     * 日志对象
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(CommonUtil.class);

    private CommonUtil() {

    }

    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * Map是否为空
     *
     * @param map Map
     * @return boolean
     * @throws Exception
     */
    public static boolean isEmptyMap(Map<?, ?> map) {
        return map == null || map.isEmpty();
    }

    /**
     * List是否为空
     *
     * @param list List
     * @return boolean
     * @throws Exception
     */
    public static boolean isEmptyList(List<?> list) {
        return list == null || list.isEmpty();
    }

    /**
     * 根据参数，返回?,?格式字符串，且设置参数信息
     *
     * @param list 需要处理的参数
     * @param params 作为过滤条件的参数
     * @return String
     * @throws Exception
     */
    public static String getJsonStr(List<?> list, List<Object> params) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : list) {
            if (sb.length() == 0) {
                sb.append("?");
            } else {
                sb.append(",?");
            }
            if (params != null) {
                params.add(obj);
            }
        }
        return sb.toString();
    }

    /**
     * 根据参数，返回?,?格式字符串，且设置参数信息
     *
     * @param list 需要处理的参数
     * @param params 作为过滤条件的参数
     * @return
     * @throws Exception
     */
    public static String getJsonStr(Object[] list, List<Object> params) {
        StringBuilder sb = new StringBuilder();
        for (Object obj : list) {
            if (sb.length() == 0) {
                sb.append("?");
            } else {
                sb.append(",?");
            }
            if (params != null) {
                params.add(obj);
            }
        }
        return sb.toString();
    }

    /**
     * 获取本地MAC地址
     *
     * @param ia InetAddress
     * @return String
     * @throws SocketException
     */
    public static String getLocalMac(InetAddress ia) throws Exception {
        // 获取网卡，获取地址
        byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
        StringBuffer sb = new StringBuffer("");
        for (int i = 0; i < mac.length; i++) {
            if (i != 0) {
                sb.append("-");
            }
            // 字节转换为整数
            int temp = mac[i] & 0xff;
            String str = Integer.toHexString(temp);
            System.out.println("每8位:" + str);
            if (str.length() == 1) {
                sb.append("0" + str);
            } else {
                sb.append(str);
            }
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 复制listMap对象
     *
     * @param datas 复制的数据
     * @return List
     * @throws Exception
     */
    public static List<Map<String, Object>> cloneListMap(List<Map<String, Object>> datas) {
        if (datas == null) {
            return null;
        }
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (Map<String, Object> data : datas) {
            Map<String, Object> temp = new HashMap<String, Object>();
            Iterator<Entry<String, Object>> iterator = data.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<String, Object> entry = iterator.next();
                temp.put(entry.getKey(), entry.getValue());
            }
            list.add(temp);
        }
        return list;
    }

    /**
     * 数组转List
     *
     * @param obj 需要处理的数组
     * @return List
     * @throws Exception
     */
    public static List<String> arrayAsList(String[] obj) {
        List<String> list = new ArrayList<String>();
        if (obj == null || obj.length == 0) {
            return list;
        }
        for (int i = 0, len = obj.length; i < len; i++) {
            list.add(obj[i]);
        }
        return list;
    }

    public static Map<String, Map<String, Object>> convertListToMap(List<Map<String, Object>> datas, String key) {
        Map<String, Map<String, Object>> result = new HashMap<String, Map<String, Object>>();
        if (isEmptyList(datas)) {
            return result;
        }
        for (Map<String, Object> data : datas) {
            result.put((String) data.get(key), data);
        }
        return result;
    }

    public static Map<String, List<Map<String, Object>>> convertListToMapGroup(List<Map<String, Object>> datas,
        String key) {
        Map<String, List<Map<String, Object>>> result = new HashMap<String, List<Map<String, Object>>>();
        if (isEmptyList(datas)) {
            return result;
        }
        for (Map<String, Object> data : datas) {
            String value = (String) data.get(key);
            if (result.containsKey(value)) {
                result.get(value).add(data);
            } else {
                List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                list.add(data);
                result.put(value, list);
            }
        }
        return result;
    }

    /**
     * list排序
     * 
     * @param datas
     * @param orderKeys
     * @param asc
     * @return
     * @throws Exception
     */
    public static void listOrder(List<Map<String, Object>> datas, String[] orderKeys, Boolean[] ascs) {
        if (datas == null) {
            return;
        }
        if (orderKeys.length != ascs.length) {
            return;
        }
        Collections.sort(datas, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                if ((o1 == null) && (o2 == null)) {
                    return 0;
                }
                if (o1 == null) {
                    return 1;
                }
                if (o2 == null) {
                    return -1;
                }
                for (int i = 0, len = orderKeys.length; i < len; i++) {
                    String orderKey = orderKeys[i];
                    final Integer oType = ascs[i] ? -1 : 1;
                    Object obj1 = o1.get(orderKey);
                    Object obj2 = o2.get(orderKey);
                    if (obj1 == null) {
                        return 1;
                    }
                    if (obj2 == null) {
                        return -1;
                    }
                    int result = 0;
                    if ((obj1 instanceof Date)) {
                        result = dateCompare(oType, obj1, obj1);
                    } else if ((obj1 instanceof String)) {
                        result = stringCompare(oType, obj1, obj2);
                    } else if (((obj1 instanceof Double)) || ((obj1 instanceof Float))) {
                        result = doubleCompare(oType, obj1, obj2);
                    } else if (((obj1 instanceof Long)) || ((obj1 instanceof Integer)) || ((obj1 instanceof Short))
                        || ((obj1 instanceof Byte))) {
                        result = longCompare(oType, obj1, obj2);
                    }
                    if (result != 0) {
                        return result;
                    }
                }
                return 0;
            }

        });
    }

    /**
     * list排序
     * 
     * @param datas
     * @param orderKeys
     * @param asc
     * @return
     */
    public static void listOrder(List<Map<String, Object>> datas, String[] orderKeys, boolean asc) {
        if (datas == null) {
            return;
        }
        Boolean[] ascs = new Boolean[orderKeys.length];
        for (int i = 0, len = orderKeys.length; i < len; i++) {
            ascs[i] = asc;
        }
        listOrder(datas, orderKeys, ascs);
    }

    /**
     * 日期大小比较
     * 
     * @param oType
     * @param obj1
     * @param obj2
     * @return
     */
    private static int dateCompare(Integer oType, Object obj1, Object obj2) {
        Date date1 = (Date) obj1;
        Date date2 = (Date) obj2;
        long d1 = date1.getTime();
        long d2 = date2.getTime();
        if (d1 < d2) {
            return oType.intValue();
        }
        if (d1 == d2) {
            return 0;
        }
        if (d1 > d2) {
            return -oType.intValue();
        }
        return 0;
    }

    /**
     * long大小比较
     * 
     * @param oType
     * @param obj1
     * @param obj2
     * @return
     */
    private static int longCompare(Integer oType, Object obj1, Object obj2) {
        long d1 = Long.valueOf(obj1.toString()).longValue();
        long d2 = Long.valueOf(obj2.toString()).longValue();
        if (d1 < d2) {
            return oType.intValue();
        }
        if (d1 == d2) {
            return 0;
        }
        if (d1 > d2) {
            return -oType.intValue();
        }
        return 0;
    }

    /**
     * double类型大小比较
     * 
     * @param oType
     * @param obj1
     * @param obj2
     * @return
     */
    private static int doubleCompare(Integer oType, Object obj1, Object obj2) {
        double d1 = Double.parseDouble(obj1.toString());
        double d2 = Double.parseDouble(obj2.toString());
        if (d1 < d2) {
            return oType.intValue();
        }
        if (d1 == d2) {
            return 0;
        }
        if (d1 > d2) {
            return -oType.intValue();
        }
        return 0;
    }

    /**
     * 字符串大小比较
     * 
     * @param oType
     * @param obj1
     * @param obj2
     * @return
     */
    private static int stringCompare(Integer oType, Object obj1, Object obj2) {
        String str1 = obj1.toString();
        String str2 = obj2.toString();
        if (str1.compareTo(str2) < 0) {
            return oType.intValue();
        }
        if (str1.compareTo(str2) == 0) {
            return 0;
        }
        if (str1.compareTo(str2) > 0) {
            return -oType.intValue();
        }
        return 0;
    }

    /**
     * 转为树结构
     *
     * @param datas 数据
     * @param pidKey 父节点字段
     * @return
     */
    public static List<Map<String, Object>> convertTree(List<Map<String, Object>> datas, String pidKey) {
        return convertTree(datas, pidKey, "id");
    }

    /**
     * 转为树结构
     *
     * @param datas 数据
     * @param pidKey 父节点字段
     * @param idKey 子节点字段
     * @return
     */
    @SuppressWarnings("unchecked")
    public static List<Map<String, Object>> convertTree(List<Map<String, Object>> datas, String pidKey, String idKey) {
        List<Map<String, Object>> trees = new ArrayList<Map<String, Object>>();
        if (CommonUtil.isEmptyList(datas)) {
            return trees;
        }
        List<Map<String, Object>> newDatas = cloneListMap(datas);
        for (Map<String, Object> data : newDatas) {
            if (ObjectUtils.isEmpty(data.get(pidKey))) {
                trees.add(data);
            }
            for (Map<String, Object> map : newDatas) {
                if (data.get(idKey).equals(map.get(pidKey))) {
                    List<Map<String, Object>> list = null;
                    if (data.containsKey("children")) {
                        list = (List<Map<String, Object>>) data.get("children");
                    } else {
                        list = new ArrayList<Map<String, Object>>();
                    }
                    list.add(map);
                    data.put("children", list);
                }
            }
        }
        return trees;
    }

    /**
     * list转Map
     * 
     * @param datas
     * @param keyName
     * @param valueName
     * @return
     * @throws Exception
     */
    public static Map<String, Object> convertListToMap(List<Map<String, Object>> datas, String keyName,
        String valueName) {
        Map<String, Object> result = new HashMap<String, Object>();
        if (CommonUtil.isEmptyList(datas)) {
            return result;
        }
        for (Map<String, Object> data : datas) {
            result.put(StringUtil.toStr(data.get(keyName)), data.get(valueName));
        }
        return result;
    }

    public static List<Object> arrayAsList(Object[] array) throws Exception {
        List<Object> list = new ArrayList<Object>();
        if (array == null || array.length == 0) {
            return list;
        }
        Collections.addAll(list, array);
        return list;
    }

    /**
     * 分页
     * 
     * @param dataList
     * @param currentPage
     * @param pageSize
     * @return
     */
    public static List<Map<String, Object>> page(List<Map<String, Object>> dataList, int currentPage, int pageSize) {
        List<Map<String, Object>> currentPageList = new ArrayList<Map<String, Object>>();
        if (dataList != null && dataList.size() > 0) {
            int currIdx = (currentPage > 1 ? (currentPage - 1) * pageSize : 0);
            for (int i = 0; i < pageSize && i < dataList.size() - currIdx; i++) {
                Map<String, Object> data = dataList.get(currIdx + i);
                currentPageList.add(data);
            }
        }
        return currentPageList;
    }

    /**
     * 树结构转list
     *
     * @param datas 数据
     * @param result 结果
     * @param childrenKey 子节点键
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static void convertTreelistToList(List<Map<String, Object>> datas, List<Map<String, Object>> result,
        String childrenKey) {
        if (StringUtil.isEmpty(childrenKey)) {
            childrenKey = "children";
        }
        for (Map<String, Object> data : datas) {
            Map<String, Object> newData = cloneObject(data);
            result.add(newData);
            if (newData.containsKey(childrenKey)) {
                if (newData.get("children") instanceof List) {
                    convertTreelistToList((List<Map<String, Object>>) newData.remove("children"), result, childrenKey);
                }
            }
        }
    }

    /**
     * list按照分组截取
     *
     * @param <T> T
     * @param list 需要分组的List
     * @param groupSize 每组大小
     * @return
     */
    public static <T> List<List<T>> splitList(List<T> list, int groupSize) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>(0);
        }
        int length = list.size();
        // 计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        List<List<T>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            newList.add(list.subList(fromIndex, toIndex));
        }
        return newList;
    }

    /**
     * 对象深度克隆---使用序列化进行深拷贝
     * 
     * 注意： 使用序列化的方式来实现对象的深拷贝，但是前提是，对象必须是实现了 Serializable接口才可以，
     * 
     * Map本身没有实现Serializable这个接口，所以这种方式不能序列化Map，也就是不能深拷贝Map。但是HashMap是可以的，因为它实现了Serializable。
     *
     * @param obj 要克隆的对象
     * 
     * @return T
     * 
     */
    @SuppressWarnings("unchecked")
    public static <T> T cloneObject(T obj) {
        T clonedObj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            clonedObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            LOGGER.error("克隆失败:" + e.getMessage(), e);
        }
        return clonedObj;
    }

    /**
     * 获取文件的md5值
     *
     * @param file 文件
     * @return md5值
     */
    public static String md5Hex(File file) {
        InputStream is = null;
        String md5Code = null;
        try {
            is = new FileInputStream(file);
            md5Code = DigestUtils.md5Hex(IOUtils.toByteArray(is));
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(is);
        }
        return md5Code;
    }

}
